<script setup lang="ts">
import { getCurrentInstance, reactive, nextTick } from 'vue'
import vueEsign from 'vue-esign'
const { proxy } = getCurrentInstance()

/* ---- */
const esign = reactive({
  show: false,
  // ----
  shade: false,
  shadeClose: true,
  bgOpacity: 0.8,
  // ----
  box: false,
  // ----
  isListener: false,
  isLandscape: false,
  conStyle: {},
  boxStyle: {},
  topStyle: {},
  btnStyle: {},
  // ----
  width: 800,
  height: 300,
  lineWidth: 4,
  isCrop: true,
  format: 'image/png',
  // ----
  title: '',
  cancel: {},
  reset: {},
  button: {}
})

/* ---- */
const open = (opt) => {
  if (window.matchMedia('(orientation: landscape)') && window.matchMedia('(orientation: landscape)').matches) {
    // 设备处于横屏状态
    esign.isLandscape = true
    // ----
    esign.conStyle = { position: 'absolute', padding: '2rem 0.5rem 3rem 0.5rem', width: '90%', height: '90%' }
  } else {
    // 设备处于竖屏状态
    esign.isLandscape = false
    // ----
    esign.conStyle = { position: 'absolute', padding: '1rem 4.5rem 1rem 5.5rem', width: '90%', height: '90%' }
  }
  // ----
  if (opt) {
    for (var key in opt) { esign[key] = opt[key] }
    esign.show = true
  }
  // ----
  nextTick(async () => {
    await initTopBtns()
    // ----
    esign.shade = true
    esign.box = true
  })
  // ----
  if (!esign.isListener) window.addEventListener('orientationchange', handlseOpen)
}
// ----
const handlseOpen = () => {
  esign.isListener = true
  // ----
  esign.shade = false
  esign.box = false
  // ----
  setTimeout(() => {
    esign.show = false
    esign.shadeClose = true
    // ----
    esign.isLandscape = false
    esign.conStyle = {}
    esign.boxStyle = {}
    esign.topStyle = {}
    esign.btnStyle = {}
    // ----
    esign.width = 800
    esign.height = 300
    esign.lineWidth = 4
    esign.isCrop = true
    esign.format = 'image/png'
    // ----
    open(esign)
  }, 300)
}
// ----
const initTopBtns = () => {
  const boxEl = proxy.$refs.forConBox
  const imgEL = proxy.$refs.forTrueWidth
  esign.height = esign.width * imgEL.offsetHeight / imgEL.offsetWidth
  // ----
  if (esign.isLandscape) {
    esign.lineWidth = 4
    // ----
    esign.boxStyle = { padding: '2rem 0.5rem 3rem 0.5rem', width: '90%', height: '90%' }
    esign.topStyle = { position: 'absolute', padding: '0 0.5rem', width: '100%', height: '2rem', top: 0, left: 0 }
    esign.btnStyle = { position: 'absolute', padding: '0 0.5rem', width: '100%', height: '3rem', left: 0, bottom: 0 }
  } else {
    esign.lineWidth = 8
    // ----
    esign.boxStyle = { padding: '1rem 4.5rem 1rem 5.5rem', width: '90%', height: '90%' }
    esign.topStyle = { position: 'absolute', padding: '0 1rem', width: `${boxEl.offsetHeight}px`, height: '5rem', top: `${(boxEl.offsetHeight - 50) / 2}px`, left: `${boxEl.offsetWidth - (boxEl.offsetHeight + 50) / 2}px`, transform: 'rotate(90deg)' }
    esign.btnStyle = { position: 'absolute', padding: '0 1rem', width: `${boxEl.offsetHeight}px`, height: '6rem', top: `${(boxEl.offsetHeight - 60) / 2}px`, left: `${- (boxEl.offsetHeight - 60) / 2}px`, transform: 'rotate(90deg)' }
  }
}
// ----
const cancel = () => { close() }
const reset = () => { if (proxy.$refs.forEsign) proxy.$refs.forEsign.reset() }
const finish = () => {
  if (proxy.$refs.forEsign) {
    proxy.$refs.forEsign.generate().then((res) => {
      const forAngle = esign.isLandscape ? 0 : -90
      rotateImage(res, forAngle, (rotateRes) => {
        const imgBackInfo = {
          url: rotateRes.url,
          W: rotateRes.W,
          H: rotateRes.H,
          suffix: esign.format.replace(/image\//g, '')
        }
        esign.button.callback && esign.button.callback(imgBackInfo)
        close()
      })
    }).catch((err) => {
      esign.button.fail && esign.button.fail(err)
    })
  }
}
const rotateImage = (image, degrees, callback) => {
  const canvas = document.createElement('canvas')
  const ctx = canvas.getContext('2d')
  const img = new Image()
  img.src = image
  img.onload = () => {
    // --是否将画布旋转并绘制图片--
    if (Number(degrees) === 0) {
      canvas.width = img.width
      canvas.height = img.height
      // ----
      ctx.drawImage(img, 0, 0)
    } else {
      canvas.width = img.height
      canvas.height = img.width
      // ----
      ctx.translate(img.height / 2, img.width / 2)
      ctx.rotate((degrees * Math.PI) / 180)
      ctx.drawImage(img, -img.width / 2, -img.height / 2)
    }
    // 图片转换为base64格式
    const result = {
      url: canvas.toDataURL('image/png'),
      W: canvas.width,
      H: canvas.height
    }
    // ----
    callback && callback(result)
  }
}
// ----
const maskClose = () => { esign.shadeClose && close() }
const close = () => {
  if (esign.isListener) window.removeEventListener('orientationchange', handlseOpen)
  // ----
  esign.shade = false
  esign.box = false
  // ----
  setTimeout(() => {
    esign.show = false
    esign.shadeClose = true
    // ----
    esign.isListener = false
    esign.isLandscape = false
    esign.conStyle = {}
    esign.boxStyle = {}
    esign.topStyle = {}
    esign.btnStyle = {}
    // ----
    esign.width = 800
    esign.height = 300
    esign.lineWidth = 4
    esign.isCrop = true
    esign.format = 'image/png'
    // ----
    esign.title = ''
    esign.cancel = {}
    esign.reset = {}
    esign.button = {}
  }, 300)
}

/* ---- */
defineExpose({
  open
})
</script>

<template>
  <div class="esignBox" v-if="esign.show">
    <div ref="forConBox" :style="esign.conStyle"><div ref="forTrueWidth" class="EGB-body"></div></div>
    <transition name="fade">
      <div class="mask" v-if="esign.shade" @click="maskClose" :style="{ background: 'rgba(0, 0, 0, ' + esign.bgOpacity + ')' }"></div>
    </transition>
    <div class="EGB-main">
      <div class="EGB-td">
        <transition name="scale">
          <div class="EGB-box" :class="{'EGB-beside-box': esign.isLandscape}" :style="esign.boxStyle" v-if="esign.box">
            <div class="EGB-top xw-flex xw-flex-align" :style="esign.topStyle">{{esign.title}}</div>
            <div class="EGB-body xw-bg-gray"><vue-esign ref="forEsign" :width="esign.width" :height="esign.height" :lineWidth="esign.lineWidth" :isCrop="esign.isCrop" :format="esign.format"/></div>
            <div class="xw-flex xw-flex-align xw-flex-justify" :style="esign.btnStyle" v-if="Number(Object.keys(esign.cancel).length) > 0 || Number(Object.keys(esign.reset).length) > 0 || Number(Object.keys(esign.button).length) > 0">
              <span :class="esign.cancel.class" @click="cancel" v-html="esign.cancel.text" v-if="Number(Object.keys(esign.cancel).length) > 0"></span>
              <span :class="esign.reset.class" @click="reset" v-html="esign.reset.text" v-if="Number(Object.keys(esign.reset).length) > 0"></span>
              <span :class="esign.button.class" @click="finish" v-html="esign.button.text" v-if="Number(Object.keys(esign.button).length) > 0"></span>
            </div>
          </div>
        </transition>
      </div>
    </div>
  </div>
</template>

<style scoped>
/* ---- */
.esignBox { position: fixed; top: 0; left: 0; right: 0; bottom: 0; z-index: 10000; }
.mask, .EGB-main { position: fixed; top: 0; left: 0; width: 100%; height: 100%; }
.EGB-main { display: table; pointer-events: none; }
.EGB-td { display: table-cell; vertical-align: middle; text-align: center; }

/* ---- */
.EGB-box { position: relative; display: inline-block; background: rgba(255, 255, 255, 1); border-radius: 1.6rem; pointer-events: auto; }
.EGB-top { font-size: 1.6rem; text-align: left; }
.EGB-body { width: 100%; height: 100%; }

/* ---- */
.EGB-beside-box { border-radius: 0.6rem; }
.EGB-beside-box .EGB-top { font-size: 0.8rem; }
.EGB-beside-box .xw-btn { padding: 0.5rem 1rem; font-size: 0.7rem; border-radius: 0.5rem; }
</style>